#include "system_control.h"
#include "client.h"
#include "camera_command/command_parse.h"
#include "camera_command/numeric_conversion.h"
#include "camera.h"
#include "image_process.h"
#include "image_save.h"
#include "device_file.h"
#include "system_constants.h"
#include <QtEndian>
#include <QTimer>
//test
#include <QDebug>
#include <QImage>
#include <QDateTime>


SystemControl::SystemControl(Client *client)
{
    system_output_.reset(client);
    connect(this, &SystemControl::sendData, system_output_.get(), &Client::onWritData);

    heartbeat_time_ = new QTimer(this);
    connect(heartbeat_time_, &QTimer::timeout, this, static_cast<void (SystemControl::*)()>(&SystemControl::heartbeatFeedback));
}

SystemControl::~SystemControl()
{

}

void SystemControl::setCameraEngine(Camera *camera)
{
    camera_device_.reset(camera);

    int init_result = camera_device_->cameraInit();
    cameraInitializationResult(init_result);

    connect(camera_device_.get(), &Camera::sigImageCaptured, this, &SystemControl::onImageCaptured);
}

void SystemControl::setImageProcessEngine(ImageProcess *image_process)
{
    thumbnail_process_.reset(image_process);
    connect(this, &SystemControl::sigGenerateUploadImage, thumbnail_process_.get(), &ImageProcess::generateUploadImage);
    connect(thumbnail_process_.get(), &ImageProcess::sigGenerateUploadImageSuccess,this , &SystemControl::onUploadImageCreateSuccess);
}

void SystemControl::setImageSaveEngine(ImageSave *image_save)
{
    file_image_.reset(image_save);
    connect(this, &SystemControl::sigAddImageAuxiliaryData, file_image_.get(), &ImageSave::setImageAuxiliaryInformation);
    connect(this, &SystemControl::sigGenerateUploadImageData, file_image_.get(), &ImageSave::imageSave);
}

void SystemControl::setDeviceFileEngine(DeviceFile *device_file)
{
    device_file_.reset(device_file);
    acquireDeviceUniqueSign();
}

void SystemControl::dataInput(QByteArray data)
{
    if(!heartbeat_time_->isActive())
        heartbeat_time_->start(1000);

    data_input_.append(data);
    DataSplit();
}

void SystemControl::onImageCaptured(unsigned char *image_pointer)
{
    if(camera_device_->getTriggerSource() == external_trigger_){
        externalTrigger();
    }

    if(pohot_mode_ == PhotoAndSave){
        //发送相机辅助信息+拼接的相机编号
//        image_auxiliary_message_.resize(100);//test
        image_auxiliary_message_.append(QByteArray(reinterpret_cast<const char *>(&image_count_index_), sizeof(unsigned int)));
        image_auxiliary_message_.append(static_cast<char>(device_number_));

        emit sigAddImageAuxiliaryData(image_auxiliary_message_);
        emit sigGenerateUploadImage(image_pointer);
        emit sigGenerateUploadImageData(image_pointer);
    }else if(pohot_mode_ == Photo){
        emit sigGenerateUploadImage(image_pointer);
    }
    ++image_count_index_;

    unsigned int current_exposure_amount = device_file_->getExposureAmount();
    device_file_->setExposureAmount(current_exposure_amount+1);
}

void SystemControl::onUploadImageCreateSuccess()
{
    QByteArray upload_image;
    thumbnail_process_->getUploadImagedata(upload_image);

    QByteArray arr;
    arr = CommandParse::BuildSendData(1, device_number_, Command::CmdPicture, upload_image);
    emit sendData(arr);
}

int SystemControl::DataSplit()
{
    QList<QByteArray> list_data;
    CommandParse::ParseCommands(data_input_, list_data);
    for(auto &v : list_data){
//        qDebug() << "ssss" << v;
        checkRecvCommand(v);
    }
    return 0;
}

bool SystemControl::checkRecvCommand(const QByteArray &cmd)
{
    const char* p_data1 = cmd.data();
    int frame_num = sizeof (Command::CommandHeader::preamble);
    bool ok;
    quint16 frame = cmd.mid(frame_num, 2).toHex().toUShort(&ok, 16);
    int code_num = sizeof (Command::CommandHeader::preamble) + sizeof (Command::CommandHeader::frameNum) + sizeof (Command::CommandHeader::cameraId);
    QByteArray data = cmd.mid(sizeof(Command::CommandHeader), cmd.size() - CommandParse::ReceiveDataMinBytes());
    switch (p_data1[code_num]) {
    case Command::RecvCameraInfo:{
//        camera_device_->getFpgaBoardTemperature();
        getCameraInfo(frame);
        return true;
    }
    case Command::RecvCameraMode:{
        setCameraMode(frame, data);
        return true;
    }
    case Command::RecvTriggerSource:{
        setTriggerSource(frame, data);
        return true;
    }
    case Command::RecvInternalTrigger:{
        triggerOne(frame);
        return true;
    }
    case Command::RecvExpTime:{
        setExposureTime(frame, data);
        return true;
    }
    case Command::RecvFrame:{
        setFrame(frame, data);
        return true;
    }
    case Command::RecvAnalogGain:{
        setAnologGain(frame, data);
        return true;
    }
    case Command::RecvHeartBeat:{
        heartbeatFeedback(frame);
        return true;
    }
    case Command::RecvOutputWindow:{
        setWindow(frame, data);
        return true;
    }
    case Command::RecvTemp:{
        getTemperature(frame);
        return true;
    }
    case Command::RecvOutputType:{
        setPictureType(frame, data);
        return true;
    }
    case Command::RecvRecover:{
        cameraRecover(frame);
        return true;
    }
    case Command::RecvSaveLocation:{
        setSaveLocation(frame, data);
        return true;
    }
    case Command::RecvSetPhotoMessage:{
        //待完善
        setPhotoMessage(frame, data);
        return true;
    }
    case Command::RecvSetPhotoBits:{
        setPhotoBit(frame, data);
        return true;
    }
    case Command::RecvClearStorage:{
        clearStorage(frame, data);
        return true;
    }
    case Command::RecvExposureCount:{
        getExposureCount(frame);
        return true;
    }
    }
    return false;
}

void SystemControl::acquireDeviceUniqueSign()
{
    device_number_ = device_file_->getDeviceNumber();
}

void SystemControl::cameraInitializationResult(int init_result)
{
    if(init_result == DEVICE_OK){
        camera_initialization_result_ = InitOK;
    }else{
        camera_initialization_result_ = InitERR;
    }
}

int SystemControl::getCameraInfo(unsigned short frame)
{
    unsigned char camera_init_result = camera_initialization_result_;
    unsigned char pohot_mode = pohot_mode_;
    unsigned char trigger_source = camera_device_->getTriggerSource();
    unsigned short exposure_time = camera_device_->getExposureTime();
    unsigned short frame_time = camera_device_->getFrameRate();
    unsigned char anolog_gain = camera_device_->getAnologGain();
    unsigned short start_x, width, start_y, height;
    thumbnail_process_->getROI(start_x, start_y, width, height);
    unsigned short sensor_temperature = camera_device_->getSensorTemperature();
    unsigned char image_output_type = camera_device_->getPictureMode();
    unsigned char image_storage_position = file_image_->getImageSavePosition();
    unsigned int internal_storage_capacity = 0, external_storage_capacity = 0;
    device_file_->getStorageCapacity(internal_storage_capacity, external_storage_capacity);

    QByteArray arr;
    QByteArray a;
    QDataStream stream(&a, QIODevice::WriteOnly);
#ifdef BigAndSmall
    stream << camera_init_result<< pohot_mode<<trigger_source<<qFromBigEndian(exposure_time)<<qFromBigEndian(frame_time)
            <<anolog_gain<<qFromBigEndian(start_x)<<qFromBigEndian(width)<<qFromBigEndian(start_y)<<qFromBigEndian(height)
           <<qFromBigEndian(sensor_temperature)<<image_output_type<<image_storage_position<<qFromBigEndian(internal_storage_capacity)
          <<qFromBigEndian(external_storage_capacity);
#else
    stream << camera_init_result<< pohot_mode<<trigger_source<<exposure_time<<frame_time
            <<anolog_gain<<start_x<<width<<start_y<<height<<sensor_temperature<<image_output_type
           <<image_storage_position<<internal_storage_capacity<<external_storage_capacity;
#endif
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdCameraInfo, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::setCameraMode(unsigned short frame, QByteArray data)
{
    pohot_mode_ = static_cast<unsigned char>(data[0]);

    QByteArray arr;
    QByteArray a;
    a.append(static_cast<char>(pohot_mode_));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdCameraMode, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::setTriggerSource(unsigned short frame, QByteArray data)
{
    unsigned char mode = static_cast<unsigned char>(data[0]);
    camera_device_->setTriggerSource(mode);

    const unsigned char current_mode = camera_device_->getTriggerSource();

    QByteArray arr;
    QByteArray a;
    a.append(static_cast<char>(current_mode));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdTriggerSource, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::triggerOne(unsigned short frame)
{
    camera_device_->trigger();

    QByteArray arr;
    QByteArray a;
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdInternalTrigger, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::setExposureTime(unsigned short frame, QByteArray data)
{
    bool ok;
    unsigned short time = data.toHex().toUShort(&ok,16);
#ifdef BigAndSmall
    time = qFromBigEndian(time);
#endif
    camera_device_->setExposureTime(time);

    time = camera_device_->getExposureTime();
#ifdef BigAndSmall
    time = qFromBigEndian(time);
#endif

    QByteArray arr;
    QByteArray a;
    a.append(NumericConversion::ShortToArray(time));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdExpTime, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::setFrame(unsigned short frame, QByteArray data)
{
    bool ok;
    unsigned short frame_rate = data.toHex().toUShort(&ok, 16);
#ifdef BigAndSmall
    frame_rate = qFromBigEndian(frame_rate);
#endif
    camera_device_->setFrameRate(frame_rate);

    frame_rate = camera_device_->getFrameRate();
#ifdef BigAndSmall
    frame_rate = qFromBigEndian(frame_rate);
#endif

    QByteArray arr;
    QByteArray a;
    a.append(NumericConversion::ShortToArray(frame_rate));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdFrame, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::setAnologGain(unsigned short frame, QByteArray data)
{
    unsigned char gain = static_cast<unsigned char>(data[0]);
    camera_device_->setAnologGain(gain);

    gain = camera_device_->getAnologGain();

    QByteArray arr;
    QByteArray a;
    a.append(static_cast<char>(gain));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdAnalogGain, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::setWindow(unsigned short frame, QByteArray data)
{
    unsigned short picStartX, picWidth, picStartY, picHeight;
    QDataStream stream(&data, QIODevice::ReadOnly);
    stream >> picStartX >> picWidth >> picStartY >> picHeight;
#ifdef BigAndSmall
    picStartX = qFromBigEndian(picStartX);
    picWidth = qFromBigEndian(picWidth);
    picStartY = qFromBigEndian(picStartY);
    picHeight = qFromBigEndian(picHeight);
#endif
    thumbnail_process_->setROI(picStartX, picStartY, picWidth, picHeight);

    thumbnail_process_->getROI(picStartX, picStartY, picWidth, picHeight);
#ifdef BigAndSmall
    picStartX = qFromBigEndian(picStartX);
    picWidth = qFromBigEndian(picWidth);
    picStartY = qFromBigEndian(picStartY);
    picHeight = qFromBigEndian(picHeight);
#endif

    QByteArray arr;
    QByteArray a;
    a.append(NumericConversion::ShortToArray(picStartX));
    a.append(NumericConversion::ShortToArray(picWidth));
    a.append(NumericConversion::ShortToArray(picStartY));
    a.append(NumericConversion::ShortToArray(picHeight));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdOutputWindow, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::getTemperature(unsigned short frame)
{
    unsigned short sensor_temperature = camera_device_->getSensorTemperature();
#ifdef BigAndSmall
    sensor_temperature = qFromBigEndian(sensor_temperature);
#endif

    QByteArray arr;
    QByteArray a;
    a.append(NumericConversion::ShortToArray(sensor_temperature));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdTemp, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::setPictureType(unsigned short frame, QByteArray data)
{
    unsigned char type = static_cast<unsigned char>(data[0]);
    camera_device_->setpictureMode(type);

    type = camera_device_->getPictureMode();

    QByteArray arr;
    QByteArray a;
    a.append(static_cast<char>(type));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdOutputType, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::cameraRecover(unsigned short frame)
{
    int reset_result = camera_device_->cameraReset();

    QByteArray arr;
    QByteArray a;
    char feedback_result;
    if(reset_result == DEVICE_OK){
        feedback_result = ResetOK;
    }else{
        feedback_result = ResetERR;
    }
    a.append(feedback_result);
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdRecover, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::setSaveLocation(unsigned short frame, QByteArray data)
{
    //如果外存储剩余容量为0，则不可以设置为外存储
    unsigned int internal_storage_capacity = 0, external_storage_capacity = 0;
    device_file_->getStorageCapacity(internal_storage_capacity, external_storage_capacity);
    unsigned char location = static_cast<unsigned char>(data[0]);
    if(external_storage_capacity != 0){
        file_image_->setImageSavePosition(location);
    }

    location = file_image_->getImageSavePosition();

    QByteArray arr;
    QByteArray a;
    a.append(static_cast<char>(location));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdSaveLocation, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::setPhotoMessage(unsigned short frame, QByteArray data)
{
    image_auxiliary_message_ = data;
    QByteArray arr;
    QByteArray a;
    a.append(static_cast<char>(device_number_));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdSetPhotoMessage, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::setPhotoBit(unsigned short frame, QByteArray data)
{
    unsigned char bits = static_cast<unsigned char>(data[0]);
    file_image_->setImageBits(bits);

    bits = file_image_->getImageBits();

    QByteArray arr;
    QByteArray a;
    a.append(static_cast<char>(bits));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdSetPhotoBits, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::clearStorage(unsigned short frame, QByteArray data)
{
    bool ok;
    unsigned char order = static_cast<unsigned char>(data[0]);
    data.remove(0,1);
    unsigned short clear_num = data.toHex().toUShort(&ok, 16);
#ifdef BigAndSmall
    clear_num = qFromBigEndian(clear_num);
#endif
    unsigned short delete_number = clear_num+2;
    int result = device_file_->clearStorage(order, delete_number);

    QByteArray arr;
    QByteArray a;
    a.append(static_cast<char>(result));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdClearStorage, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::getExposureCount(unsigned short frame)
{
    unsigned int current_exposure_amount = device_file_->getExposureAmount();
#ifdef BigAndSmall
    current_exposure_amount = qFromBigEndian(current_exposure_amount);
#endif

    QByteArray arr;
    QByteArray a;
    a.append(NumericConversion::IntToArray(current_exposure_amount));
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdExposureCount, a);
    emit sendData(arr);

    return DEVICE_OK;
}

int SystemControl::heartbeatFeedback(unsigned short frame)
{
    QByteArray arr;
    QByteArray a;
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdHeartBeat, a);
    emit sendData(arr);

    return DEVICE_OK;
}

void SystemControl::heartbeatFeedback()
{
    QByteArray arr;
    QByteArray a;
    arr = CommandParse::BuildSendData(0x1, device_number_, Command::CmdHeartBeat, a);
    emit sendData(arr);
}

void SystemControl::cameraMalfunction(unsigned short frame, unsigned char data)
{
    QByteArray arr;
    QByteArray a;
    a.append(data);
    arr = CommandParse::BuildSendData(frame, device_number_, Command::CmdDeviceError, a);
    emit sendData(arr);
}

void SystemControl::externalTrigger()
{
    QByteArray arr;
    QByteArray a;
    arr = CommandParse::BuildSendData(0x0, device_number_, Command::CmdExternExposure, a);
    emit sendData(arr);
}
